import axios, {
	AxiosInstance,
	AxiosResponse,
	CreateAxiosDefaults,
	InternalAxiosRequestConfig,
} from "axios";
import { hideLoading } from "./loading";

type codeType = "401" | "403" | "404" | "408" | "500";

/** 请求和响应拦截器函数类型 */
type InterceptorsOption = {
	/** 自定义请求拦截 */
	requestInterceptors?: InterceptorsReqOption;
	/** 自定义响应拦截 */
	responseInterceptors?: InterceptorsResOption;
};

type InterceptorsReqOption = {
	success?: ((req: InternalAxiosRequestConfig) => InternalAxiosRequestConfig) | null;
	error?: ((err: any) => Promise<any>) | null;
};

type InterceptorsResOption = {
	success?: ((res: AxiosResponse) => any) | null;
	error?: ((err: any) => Promise<any>) | null;
	throwError?: boolean;
};

export class BaseHttp {
	private static instance: null | AxiosInstance = null;
	private static defInstance: AxiosInstance = generateDefInstance({
		timeout: 3000,
	});

	static createInstance(
		option?: CreateAxiosDefaults<any>,
		interceptorsOption?: InterceptorsOption
	) {
		this.instance = generateDefInstance(option, interceptorsOption);
	}

	/** 默认使用 defInstance 配置 如果 instance 存在则使用 instance */
	static getInstance() {
		return BaseHttp.instance || BaseHttp.defInstance;
	}
}

/** 请求错误处理 */
export class RequestError {
	private static errorCallbacks: Map<codeType, (message: string) => void> = new Map();
	constructor(errorCode: codeType, message: string) {
		RequestError.disposeError(errorCode, message);
	}
	static registoyError(errorCode: codeType, errorCallback: (message: string) => void) {
		this.errorCallbacks.set(errorCode, errorCallback);
	}
	private static disposeError(errorCode: codeType, message: string) {
		if (errorCode) {
			const fn = this.errorCallbacks.get(errorCode);
			fn && fn(message);
		} else {
			console.error(errorCode + "没有注册错误回调");
		}
	}
}

/** 生成请求拦截器 */
function generateDefInstance(
	option?: CreateAxiosDefaults<any>,
	interceptorsOption?: InterceptorsOption
) {
	const instance = axios.create(option);
	generateRequestInterceptors(instance, interceptorsOption?.requestInterceptors);
	generateResponseInterceptors(instance, interceptorsOption?.responseInterceptors);
	return instance;
}

/** 生成默认请求拦截 */
function generateRequestInterceptors(instance: AxiosInstance, option?: InterceptorsReqOption) {
	const defReqSuccess = (req: InternalAxiosRequestConfig) => {
		// 断网提示
		if (!navigator.onLine) {
			setTimeout(function () {
				hideLoading();
			}, 100);
		}
		return req;
	};
	const defReqError = (error: any) => {
		return Promise.resolve(error);
	};

	instance.interceptors.request.use(
		option?.success || ((req: any) => defReqSuccess(req)),
		option?.error || defReqError
	);
}

/** 生成默认响应拦截 */
function generateResponseInterceptors(instance: AxiosInstance, option?: InterceptorsResOption) {
	const defResSuccess = (res: AxiosResponse) => {
		const auth = res.headers.authorization;
		if (auth) {
			sessionStorage.setItem("authorization", auth);
		}
		return { ...res?.data, ...res?.data.data };
	};

	const defResError = (error: any) => {
		setTimeout(function () {
			hideLoading();
		}, 100);
		/** 错误处理 */
		error.response &&
			new RequestError(error.response?.status?.toString(), error.response?.data?.message);
		return Promise.resolve({});
	};
	instance.interceptors.response.use(
		res => {
			if (option?.success) {
				return option.success(res);
			} else {
				return defResSuccess(res);
			}
		},
		error => {
			if (option?.error) {
				error.response &&
					new RequestError(
						error.response?.status?.toString(),
						error.response?.data?.message
					);
				return option.error(error);
			} else {
				return defResError(error);
			}
		}
	);
}
